package com.cskaoyan.javase.recursion._0introduction;

/**
 * 递归的定义:
 * 们已经学习过方法，使用过方法了。
 * 方法体中是可以调用方法的，那么如果在方法体中调用方法自身呢？
 *
 * 特别的，在一个方法当中再次调用这个方法，就像故事里提到同样的故事一样
 * 我们把方法在运行时调用自身的情况，称之为递归，又叫做递归调用。
 *
 * 递归的使用:
 *      1.要想使用递归,必须在方法体中存在自身调用自身的语句
 *          也就是"递归体"语句
 *          递归体对递归而言,是必不可少的
 *
 *      2.只有递归体的递归是不合法的,是不可用的,一定会栈溢出
 *          为了让递归能够正常运行
 *          必须要明确递归停止的条件
 *          这被称之为"递归的出口"
 *          递归的出口对一个合法的递归是必不可少的
 *
 *      递归体和递归的出口是递归的两要素,使用递归必须要有它们.
 *
 *      3.思考:
 *          递归有递归体和递归的出口以后,就一定能够正常运行吗?
 *          不一定
 *          如果递归的出口过于遥远
 *          导致递归的次数,仍然超出了栈内存的大小
 *          依然会导致栈溢出错误.
 *          使用递归不仅要考虑出口,还需要考虑递归的次数(递归的深度)
 *          递归的深度也不能超出栈内存的大小
 *
 * 以上总结,递归的使用是非常危险的,稍有不慎就会栈溢出.
 * 所以在实际开发中,尽量避免使用递归
 * 如果确实要用递归,那就考虑清楚递归的上述三个要求.
 *
 * @since 11:48
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*
            分析:
            sum(10) = 10 + sum(9);
            sum(9) = 9 + sum(8);
            sum(8) = 8 + sum(7);
            ...
            显然以上过程是停不下来的,会一直进行下去
            那么程序的运行结果是什么呢?
                1.死循环
                2.运行报错,程序终止执行
                3.电脑受不了了,自己炸了(这是错误选择)
            运行代码发现,程序并没有死循环,而是报错终止执行
            程序抛出了异常: StackOverflowError 栈溢出错误

            StackOverflowError仍然是一个异常
            和数组下标越界,空指针异常都是同一种东西
            只不过Error是更为严重的错误

            为什么会栈溢出?什么栈溢出了?
            栈溢出,指的是栈内存不够用,导致程序出错
            指的是JVM栈溢出了.
            Method 'sum()' recurses infinitely, and can only end by throwing an exception
            因为方法栈帧只进不出,导致栈内存不够用,溢出

            那么如何来避免栈溢出,让递归正常运行吗?
            只需要给出一个条件,让递归能够停止,让方法栈帧能够出栈
            这样就能够避免栈溢出


            现在递归有出口以后:
            if (num == 0){
                return 0;
            }
            sum(10) = 55;
         */
        System.out.println(sum(100));
        System.out.println(sum(16000));

    }

    // 递归求和,其中num是大于0的
    public static int sum(int num) {
        // 给出一个条件,让递归停止
        // 递归的出口
        if (num == 0){
            return 0;
        }
        return num + sum(num - 1);
    }

}
